from collections import OrderedDict
from importlib import import_module

from django.urls import re_path
from rest_framework.routers import DefaultRouter
from rest_framework.urlpatterns import format_suffix_patterns


class ReloadRouter(DefaultRouter):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.api_root_dict = None
        self.registry = {}

    def register(self, prefix, viewset, basename=None):
        if basename is None:
            basename = self.get_default_basename(viewset)
        self.registry.update({basename: (prefix, viewset, basename)})

        # invalidate the urls cache
        if hasattr(self, '_urls'):
            del self._urls

    def load_url(self, prefix, viewset, basename=None):
        if basename is None:
            basename = self.get_default_basename(viewset)
        lookup = self.get_lookup_regex(viewset)
        routes = self.get_routes(viewset)
        ret = []
        for route in routes:

            # Only actions which actually exist on the viewset will be bound
            mapping = self.get_method_map(viewset, route.mapping)
            if not mapping:
                continue

            # Build the url pattern
            regex = route.url.format(
                prefix=prefix,
                lookup=lookup,
                trailing_slash=self.trailing_slash
            )

            # If there is no prefix, the first part of the url is probably
            #   controlled by project's urls.py and the router is in an app,
            #   so a slash in the beginning will (A) cause Django to give
            #   warnings and (B) generate URLS that will require using '//'.
            if not prefix and regex[:2] == '^/':
                regex = '^' + regex[2:]

            initkwargs = route.initkwargs.copy()
            initkwargs.update({
                'basename': basename,
                'detail': route.detail,
            })

            view = viewset.as_view(mapping, **initkwargs)
            name = route.name.format(basename=basename)
            ret.append(re_path(regex, view, name=name))
        return ret

    def get_urls(self):
        """
        Use the registered viewsets to generate a list of URL patterns.
        """
        ret = []

        for prefix, viewset, basename in self.registry.values():
            ret.extend(self.load_url(prefix, viewset, basename))
        if self.include_root_view:
            api_root_view = self.get_api_root_view(api_urls=ret)
            root_url = re_path(r'^$', api_root_view, name=self.root_view_name)
            ret.append(root_url)

        if self.include_format_suffixes:
            ret = format_suffix_patterns(ret)

        return ret

    def get_api_root_view(self, api_urls=None):
        """
        Return a basic root view.
        """
        self.api_root_dict = OrderedDict()
        list_name = self.routes[0].name
        for prefix, viewset, basename in self.registry.values():
            self.api_root_dict[prefix] = list_name.format(basename=basename)

        return self.APIRootView.as_view(api_root_dict=self.api_root_dict)

    def cancel(self, basename):
        if self.registry.get(basename):
            del self.registry[basename]
        # invalidate the urls cache
        if hasattr(self, '_urls'):
            del self._urls
